package dao

import (
	"context"
	"github.com/go-redis/redis/v8"
	"github.com/streadway/amqp"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"mall-portalv2/bootstrap"
	"mall-portalv2/conf"
	"mall-portalv2/global"
	"mall-portalv2/library/mq"
	"mall-portalv2/library/orm"
	"mall-portalv2/library/redisclient"
	"time"
)

/**
* Author: joker
* TODO: test
* Date: 2022/8/18
* Time: 上午10:43
**/

// Dao dao.
type Dao struct {
	db *gorm.DB
	rc *redis.Client
	mq *mq.RabbitMQ
}

// New a dao and return.
func New() (dao *Dao) {
	var (
		dc struct {
			Conf *orm.Config
		}
		rc struct {
			Conf *redisclient.RedisConfig
		}
	)

	dao = &Dao{}

	dc.Conf = &orm.Config{
		Debug:           conf.Config.System.Debug,
		User:            conf.Config.Mysql.User,
		Password:        conf.Config.Mysql.Password,
		Host:            conf.Config.Mysql.Host,
		Port:            conf.Config.Mysql.Port,
		DbName:          conf.Config.Mysql.DbName,
		Params:          conf.Config.Mysql.Params,
		TablePrefix:     conf.Config.Mysql.TablePrefix,
		ConnMaxLifetime: conf.Config.Mysql.ConnMaxLifetime,
		MaxOpenConns:    conf.Config.Mysql.MaxOpenConns,
		MaxIdleConns:    conf.Config.Mysql.MaxIdleConns,
	}
	if conf.Config.Mysql.IsUse {
		db, err := dc.Conf.InitMysql()
		if err != nil {
			global.Log.Panic("mysql init ctx", zap.Error(err))
		}
		dao.db = db
		global.DB = db
	}

	if conf.Config.Redis.IsUse {
		global.Log.Info("链接redis")
		rc.Conf = &redisclient.RedisConfig{
			Password: conf.Config.Redis.Password,
			Host:     conf.Config.Redis.Host,
			Port:     conf.Config.Redis.Port,
			DbName:   conf.Config.Redis.DbName,
		}
		var (
			rdbc *redis.Client
			err  error
		)
		rdbc, err = rc.Conf.InitRedisClient()
		if err != nil {
			global.Log.Panic("redis init ctx", zap.Error(err))
		}
		dao.rc = rdbc
		global.Redis = rdbc
	}

	if conf.Config.RabbitMq.IsUse {
		connectClient := []mq.Producer{}
		connectClient = append(connectClient, mq.Producer{
			Type: 1,
			Exchange: mq.Exchange{
				Name:       "mall.order.ttl.direct",
				Kind:       "topic",
				Durable:    true,
				AutoDelete: false,
				Internal:   false,
				NoWait:     false,
				Arg:        nil,
			},
			Queue: mq.Queue{
				Name:       "mall.order.ttl",
				Durable:    false,
				AutoDelete: false,
				Internal:   false,
				NoWait:     false,
				Arg: amqp.Table{
					"x-message-ttl":             1000 * 60 * 60 * 24 * 15,       // 消息过期时间,毫秒 15天
					"x-dead-letter-exchange":    "mall.order.ttl.cancel.direct", // 指定死信交换机
					"x-dead-letter-routing-key": "",
				},
			},
		})
		connectClient = append(connectClient, mq.Producer{
			Type: 2,
			Exchange: mq.Exchange{
				Name:       "mall.order.ttl.cancel.direct",
				Kind:       "topic",
				Durable:    true,
				AutoDelete: false,
				Internal:   false,
				NoWait:     false,
				Arg:        nil,
			},
			Queue: mq.Queue{
				Name:       "mall.order.ttl.cancel",
				Durable:    false,
				AutoDelete: false,
				Internal:   false,
				NoWait:     false,
				Arg:        nil,
			},
		})
		dao.mq = mq.NewRabbitMQ(&mq.RabbitMQConf{
			Dns: conf.Config.RabbitMq.Dns,
		}, connectClient)
	}

	bootstrap.InitWechatCron()
	return
}

// Close  the resource.
func (d *Dao) Close() {
	d.rc.Close()
	//d.db.Unscoped()
}

// Ping ping the resource.
func (d *Dao) Ping(ctx context.Context) (err error) {
	if err = d.pingRedis(ctx); err != nil {
		return
	}
	return d.Ping(ctx)
}

func (d *Dao) pingRedis(ctx context.Context) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	_, err := d.rc.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}
